/**
 * 
 */
package mas;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import org.apache.commons.math3.random.MersenneTwister;
import org.apache.commons.math3.random.RandomGenerator;

import com.google.common.math.DoubleMath;

import rinde.sim.core.graph.Point;
import rinde.sim.core.model.pdp.PDPModel;
import rinde.sim.core.model.pdp.Parcel;
import rinde.sim.core.model.road.RoadModel;
import rinde.sim.util.TimeWindow;
/**
 * @author IVAN
 * @description This class represents a box on the Dynamic PDP
 */
public class Box extends Parcel{

	protected int pickupZoneNumber;
	protected int deliveryZoneNumber;
	protected long arrivalTime;
	protected Truck currentAgent;
	protected int boxNumber;
	protected Point pPickup;
	protected Point pDelivery;
	//when have the pickup and delivery actually happened (necessary for scoring the experiment)
	protected long actualPickupTime;
	protected long actualDeliveryTime;
	protected boolean isAttended;
	protected boolean isReserved;
	protected boolean delivered;
	private long reportedPickupTime;
	private long reportedDeliveryTime;

	
	/**
	 * Retrieves a box number
	 * @return
	 */
	public int getBoxNumber() {
		return boxNumber;
	}

	/**
	 * Sets unique id
	 * @param boxNumber
	 */
	public void setBoxNumber(int boxNumber) {
		this.boxNumber = boxNumber;
	}

	
	public Truck getCurrentAgent() {
		return currentAgent;
	}

	public void setCurrentAgent(Truck currentAgent) {
		this.currentAgent = currentAgent;
	}

	public long getArrivalTime() {
		return arrivalTime;
	}

	public void setArrivalTime(long arrivalTime) {
		this.arrivalTime = arrivalTime;
	}

	
	public boolean isReserved() {
		return isReserved;
	}

	public void setReserved(boolean isReserved) {
		this.isReserved = isReserved;
	}

	public Point getpPickup() {
		return pPickup;
	}

	public Point getpDelivery() {
		return pDelivery;
	}
	
	public boolean isDelivered(){
		return delivered;
	}
	
	public void setDelivered(boolean bool){
		this.delivered = bool;
	}

	public boolean isAttended() {
		return isAttended;
	}

	public void setAttended(boolean isAttended) {
		this.isAttended = isAttended;
	}

	public void setpPickup(Point pPickup) {
		this.pPickup = pPickup;
	}

	public int getPickupZoneNumber() {
		return this.pickupZoneNumber;
	}

	public void setPickupZoneNumber(int pickupZoneNumber) {
		this.pickupZoneNumber = pickupZoneNumber;
	}
	
	
	public void setpDelivery(Point pDelivery) {
		this.pDelivery = pDelivery;
	}
	
	public int getDeliveryZoneNumber() {
		return this.deliveryZoneNumber;
	}

	public void setDeliveryZoneNumber(int deliveryZoneNumber) {
		this.deliveryZoneNumber = deliveryZoneNumber;
	}
	
	public long getActualPickupTime() {
		return actualPickupTime;
	}

	public void setActualPickupTime(long actualPickupTime) {
		this.actualPickupTime = actualPickupTime;
	}

	public long getActualDeliveryTime() {
		return actualDeliveryTime;
	}

	public void setActualDeliveryTime(long actualDeliveryTime) {
		this.actualDeliveryTime = actualDeliveryTime;
	}

	public Box(long arrivalTime, Point pPickup, long pPickupDuration, TimeWindow pickupTW,
			Point pDestination, long pDeliveryDuration, TimeWindow deliveryTW) {
		super(pDestination, pPickupDuration, pickupTW, pDeliveryDuration, deliveryTW,
				0); //magnitude = 0, no limiting capacity
		this.arrivalTime = arrivalTime;
		this.pPickup = pPickup; 
		this.pDelivery = pDestination;
		setStartPosition(pPickup);
	}

	@Override
	public void initRoadPDP(RoadModel pRoadModel, PDPModel pPdpModel) {
		
	}
	
	/**
	 * Test box arrivals at fix intervals
	 * @param roadModel
	 * @return
	 */
	public static List<Box> generateBoxes(RoadModel roadModel){
		//initialization
		int maxBoxes = App.testingBoxes,i = 1;
		long arrivalInterval = 200*App.TIME_MULTIPLIER;
		long pickupInterval = 800*App.TIME_MULTIPLIER;
		long deliveryInterval = 800*App.TIME_MULTIPLIER;
		long pickupDuration = 10*App.TIME_MULTIPLIER;
		long deliveryDuration = 10*App.TIME_MULTIPLIER;
		
		RandomGenerator rng = new MersenneTwister(129);
		List<Box> boxes = new ArrayList<Box>(maxBoxes);
		//Create boxes
		for (i=1;i<=maxBoxes;i++){
			TimeWindow ptw = new TimeWindow(arrivalInterval*i+ pickupInterval, (arrivalInterval*i) + 2*pickupInterval);
			TimeWindow dtw = new TimeWindow((arrivalInterval*i) + 2*pickupInterval, (arrivalInterval*i) + 2*pickupInterval + deliveryInterval);
			
			Box newBox = new Box(arrivalInterval*i, roadModel.getRandomPosition(rng), pickupDuration, ptw,
					roadModel.getRandomPosition(rng), deliveryDuration, dtw);	
			newBox.setAttended(false);
			newBox.setBoxNumber(i);
			boxes.add(newBox);
		}		
		return boxes;		
	}
	
	/**
	 * Load data set to produce requests (boxes)
	 * @param datasetFileName
	 * @return
	 */
	public static List<Box> generateBoxes(String datasetFileName, RoadModel roadModel){ //double x_origin, double y_origin ){
		//local variables
		BufferedReader br;
		RandomGenerator rng = new MersenneTwister(123);
		String line;
		//Double pickupXPos,pickupYPos,deliveryXPos,deliveryYPos;
		Long pPickupDuration,pDeliveryDuration,pickupTWstart, pickupTWend, deliveryTWstart, deliveryTWend, arrivalTime;		
		List<Box> boxes = new ArrayList<Box>();
		try {
			br = new BufferedReader(new FileReader(datasetFileName));		
			line = br.readLine(); 
			while ((line = br.readLine()) != null) {
				StringTokenizer tokens=new StringTokenizer(line);
 				while(tokens.hasMoreTokens()){
					//arrival time
					arrivalTime = DoubleMath.roundToLong(
				            Double.parseDouble(tokens.nextToken()) * App.TIME_MULTIPLIER,
				            RoundingMode.HALF_EVEN);
							
					//pickup time
					pPickupDuration = Long.valueOf(tokens.nextToken())*App.TIME_MULTIPLIER;
					tokens.nextToken(); tokens.nextToken();
					Point pPickup = roadModel.getRandomPosition(rng);
					pickupTWstart = DoubleMath.roundToLong(
				            Double.parseDouble(tokens.nextToken()) * App.TIME_MULTIPLIER,
				            RoundingMode.HALF_EVEN);
					pickupTWend = DoubleMath.roundToLong(
				            Double.parseDouble(tokens.nextToken()) * App.TIME_MULTIPLIER,
				            RoundingMode.HALF_EVEN);
					TimeWindow pickupTW = new TimeWindow(pickupTWstart,pickupTWend);
					//delivery time
					pDeliveryDuration = Long.valueOf(tokens.nextToken())*App.TIME_MULTIPLIER;
					tokens.nextToken(); tokens.nextToken();
					Point pDestination = roadModel.getRandomPosition(rng);
					deliveryTWstart = DoubleMath.roundToLong(
				            Double.parseDouble(tokens.nextToken()) * App.TIME_MULTIPLIER,
				            RoundingMode.HALF_EVEN);
					deliveryTWend = DoubleMath.roundToLong(
				            Double.parseDouble(tokens.nextToken()) * App.TIME_MULTIPLIER,
				            RoundingMode.HALF_EVEN);
					TimeWindow deliveryTW = new TimeWindow(deliveryTWstart,deliveryTWend);
					
					Box newBox = new Box(arrivalTime, pPickup, pPickupDuration, pickupTW,
							pDestination, pDeliveryDuration, deliveryTW);	
					newBox.setAttended(false);
					boxes.add(newBox);
			    }
			}
			br.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return boxes;		
	}

	public void setReportedPickupTime(long l) {
		this.reportedPickupTime = l;		
	}

	public long getReportedPickupTime() {
		return reportedPickupTime;
	}

	public long getReportedDeliveryTime() {
		return reportedDeliveryTime;
	}

	public void setReportedDeliveryTime(long reportedDeliveryTime) {
		this.reportedDeliveryTime = reportedDeliveryTime;
	}
	
}
